/*
 *  Copyright 2013 Utkin Dmitry
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <QDebug>
#include <QStringList>
#include <QDateTime>
#include <QHostAddress>
#include <QCoreApplication>
#include <protoqtrpc/location/LocationServiceClient.h>

#define TEST_ASSERT(expr, descr...) \
    if (!(expr)) qFatal(descr);


namespace protoqtrpc {
namespace location {

// QDebug stream must be without reference
QDebug operator<<(QDebug stream, const LocationServiceClient::ServerInfo& serverInfo)
{
    qDebug() << "\n\n================================\n"
                << "Server\n  name: " << serverInfo.name
                << "\n  description: " << serverInfo.description
                << "\n  host: " << serverInfo.host
                << "\n  port: " << serverInfo.port
                << "\n  time: " << serverInfo.time;
    return stream;
}

QDebug operator<<(QDebug stream, const LocationServiceClient::ServiceInfo& serviceInfo)
{
    stream << "-------------\nService\n  name: " << serviceInfo.name
           << "\n  description: " << serviceInfo.description
           << "\n  time: " << serviceInfo.time;
    return stream;
}

void startTest()
{
    LocationServiceClient client;
    LocationServiceClient::Status status;

    QStringList testServerNames;
    testServerNames << QString::fromUtf8("test_server_1")
                    << QString::fromUtf8("test_server_2");


    // try to unregister old servers
    {
        for (int i = 0; i < 2; ++i)
        {
            status = client.unregisterServer(testServerNames[i]);
            qDebug() << (status == LocationServiceClient::STATUS_SUCCESS ?
                             "Old server unregistered" : "Server was not registered yet");
        }
    }

    // register 2 servers
    {
        quint16 port = 0;
        for (int serverId = 0; serverId < 2; ++serverId)
        {
            status = client.registerServer(testServerNames[serverId],
                                           QString("Test server N%1").arg(serverId),
                                           port);

            qDebug() << "Allocated port: " << port;

            // register 5 services per server
            for (int svcId = 1; svcId < 5; ++svcId)
            {
                status = client.registerService(
                            testServerNames[serverId],
                            QString("protoqtrpc.test.Service%1").arg(svcId),
                            QString("protoqtrpc test service N%1").arg(svcId));

                TEST_ASSERT(status == LocationServiceClient::STATUS_SUCCESS,
                            "Failed to register service: %d", status);
            }
        }
    }

    // dump registered servers and services
    {

        QList<LocationServiceClient::ServerServicesInfo> infos;
        status = client.getServersInfo(infos);

        TEST_ASSERT(status == LocationServiceClient::STATUS_SUCCESS,
                    "Failed to getServersInfo: %d", status);

        foreach (const LocationServiceClient::ServerServicesInfo& info, infos)
        {
            qDebug() << info.serverInfo;

            foreach (const LocationServiceClient::ServiceInfo& service, info.servicesInfo)
            {
                qDebug() << service;
            }
        }
    }

    // locate services
    {
        // basic test

        QList<LocationServiceClient::ServiceLocation> serviceLocations;
        status = client.locateService(QString::fromUtf8("protoqtrpc.test.Service2"),
                                      serviceLocations);
        TEST_ASSERT(status == LocationServiceClient::STATUS_SUCCESS,
                    "Failed to locate service: %d", status);

        qDebug() << "******************************\n\nLocate service results\n";

        foreach (const LocationServiceClient::ServiceLocation& location, serviceLocations)
        {
            qDebug() << location.serverInfo << location.serviceInfo;
        }

        TEST_ASSERT(serviceLocations.size() == 2, "Failed to test service locating");



        serviceLocations.clear();
        status = client.locateService(QString::fromUtf8("protoqtrpc.test.Service2"),
                                      serviceLocations,
                                      QHostAddress::LocalHost,
                                      testServerNames[1]);
        TEST_ASSERT(status == LocationServiceClient::STATUS_SUCCESS,
                    "Failed to locate service: %d", status);

        qDebug() << "******************************\n\nLocate service results\n";

        foreach (const LocationServiceClient::ServiceLocation& location, serviceLocations)
        {
            qDebug() << location.serverInfo << location.serviceInfo;
        }

        TEST_ASSERT(serviceLocations.size() == 1, "Failed to test service locating");

    }

    // unregister test servers with services
    {
        for (int i = 0; i < 2; ++i)
        {
            status = client.unregisterServer(testServerNames[i]);
            TEST_ASSERT(status == LocationServiceClient::STATUS_SUCCESS,
                        "Failed to unregister server: %d", status);
        }
    }
}

}
}


int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);

    protoqtrpc::location::startTest();

    return 0;
}
